package com.ggb.reactive.controller.user

import com.ggb.reactive.constant.JwtClaimsConstant
import com.ggb.reactive.constant.MessageConstant
import com.ggb.reactive.domain.dto.ShoppingCartDTO
import com.ggb.reactive.domain.entity.ShoppingCart
import com.ggb.reactive.extension.log
import com.ggb.reactive.model.WebResult
import com.ggb.reactive.repository.DishRepository
import com.ggb.reactive.repository.SetmealRepository
import com.ggb.reactive.repository.ShoppingCartRepository
import com.ggb.reactive.service.ShoppingCartService
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import lombok.RequiredArgsConstructor
import org.springframework.beans.BeanUtils
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.*
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono

@RestController
@RequestMapping("/user/shoppingCart")
@RequiredArgsConstructor
@Tag(name = "购物车相关")
class ShoppingCartController(
    private val shoppingCartService: ShoppingCartService,
    private val shoppingCartRepository: ShoppingCartRepository,
    private val dishRepository: DishRepository,
    private val setmealRepository: SetmealRepository

) {
    @PostMapping("/add")
    @Operation(summary = "添加购物车")
    @Transactional
    fun add(@RequestBody shoppingCartDTO: ShoppingCartDTO, exchange: ServerWebExchange): Mono<WebResult<String>> {
        val userId = (exchange.attributes[JwtClaimsConstant.USER_ID] as Int).toLong()

        val shoppingCart = ShoppingCart()
        BeanUtils.copyProperties(shoppingCartDTO, shoppingCart)
        shoppingCart.userId = userId

        return shoppingCartService.findShoppingCartByCriteria(shoppingCart)
            .flatMap { it ->

                if (it.isNotEmpty()) {
                    val cart = it.first()
                    val number = cart.number?.plus(1) ?: 0
                    log.info("cart {}",cart)
                    log.info("number {}",number)
                    shoppingCartRepository.updateNumberById(number, cart.id!!)
                } else {

                    val dishMono = shoppingCartDTO.dishId?.let { dishRepository.findById(it) }
                    val setmealMono =  shoppingCartDTO.setmealId?.let { setmealRepository.findById(it) }
                    setmealMono?.flatMap { setmeal ->
                        val item = ShoppingCart()
                        item.userId = userId
                        item.name = setmeal.name
                        item.image = setmeal.image
                        item.amount = setmeal.price
                        item.setmealId = setmeal.id
                        item.number = 1
                        shoppingCartRepository.save(item)
                    }
                        ?: (dishMono?.flatMap { dish ->
                            val item = ShoppingCart()
                            item.userId = userId
                            item.name = dish.name
                            item.image = dish.image
                            item.amount = dish.price
                            item.dishId = dish.id
                            item.number = 1
                            shoppingCartRepository.save(item)
                        } ?: Mono.empty())
                }
            }.map<WebResult<String>?> {
                WebResult.success()
            }
            .onErrorResume {
                Mono.just(WebResult.error(it.message ?: MessageConstant.ACTION_FAIL))
            }
    }


    @PostMapping("/sub")
    @Operation(summary = "减去购物车")
    @Transactional
    fun sub(@RequestBody shoppingCartDTO: ShoppingCartDTO,exchange: ServerWebExchange): Mono<WebResult<String>> {
        val userId = (exchange.attributes[JwtClaimsConstant.USER_ID] as Int).toLong()

        val shoppingCart = ShoppingCart()
        BeanUtils.copyProperties(shoppingCartDTO, shoppingCart)
        shoppingCart.userId = userId

        return shoppingCartService.findShoppingCartByCriteria(shoppingCart)
            .flatMap {
                val cart = it.firstOrNull() ?: return@flatMap Mono.just(WebResult.error(MessageConstant.SHOPPING_CART_NOT_FIND))
                val number = cart.number?.plus(-1) ?: 0
                if(number == 0){
                    shoppingCartRepository.delete(cart)
                        .then(Mono.fromCallable { WebResult.success(MessageConstant.ACTION_SUCCESS) })
                }else{
                    shoppingCartRepository.updateNumberById(number, cart.id!!)
                        .then(Mono.fromCallable { WebResult.success(MessageConstant.ACTION_SUCCESS) })
                }
            }
            .onErrorResume {
                Mono.just(WebResult.error(it.message ?: MessageConstant.ACTION_FAIL))
            }
    }

    @GetMapping("/list")
    @Operation(summary = "获取购物车列表")
    fun list(exchange: ServerWebExchange): Mono<WebResult<List<ShoppingCart>>> {
        val userId = (exchange.attributes[JwtClaimsConstant.USER_ID] as Int).toLong()
        val shoppingCart = ShoppingCart()
        shoppingCart.userId = userId
        return shoppingCartService.findShoppingCartByCriteria(shoppingCart).map {
            WebResult.success(it)
        }
            .onErrorResume {
                println("error: $it")
                Mono.just(WebResult.error(it.message ?: MessageConstant.ACTION_FAIL))
            }
    }

    @DeleteMapping("/clean")
    @Operation(summary = "清空购物车")
    fun clean(exchange: ServerWebExchange): Mono<WebResult<String>> {
        val userId = (exchange.attributes[JwtClaimsConstant.USER_ID] as Int).toLong()
        return shoppingCartRepository.deleteAllByUserId(userId).then(Mono.just(WebResult.success()))
    }
}